package com.tianji.learning.service.impl;

import cn.hutool.core.io.unit.DataUnit;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constans.RedisConstants;
import com.tianji.learning.domain.po.PointsRecord;
import com.tianji.learning.domain.vo.PointsStatisticsVO;
import com.tianji.learning.enums.PointsRecordType;
import com.tianji.learning.mapper.PointsRecordMapper;
import com.tianji.learning.mq.message.SignInMessage;
import com.tianji.learning.service.IPointsRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 学习积分记录，每个月底清零 服务实现类
 * </p>
 *
 * @author mxl
 * @since 2024-06-28
 */
@Service
@RequiredArgsConstructor
public class PointsRecordServiceImpl extends ServiceImpl<PointsRecordMapper, PointsRecord> implements IPointsRecordService {

    private final RedisTemplate redisTemplate;

    @Override
    public void addPointRecord(SignInMessage msg, PointsRecordType type) {
        // 0. 校验消息
        if(msg == null || type == null) return;

        // 1. 判断该积分类型是否存在上限
        int maxPoints = type.getMaxPoints();
        // 2. 如果有上限，查询该用户该积分类型今日已得积分数目  user time type
        if(maxPoints > 0){
            QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
            wrapper.eq("user_id", msg.getUserId());
            wrapper.eq("type", type);
            wrapper.between("create_time", DateUtils.getDayStartTime(LocalDateTime.now()), DateUtils.getDayEndTime(LocalDateTime.now()));
            wrapper.select("sum(points) as totalPoints");
            Map<String, Object> map = this.getMap(wrapper);
            Integer totalPoints = 0;
            if(map != null){
                totalPoints = ((BigDecimal) map.get("totalPoints")).intValue();
            }
            if(totalPoints >= maxPoints){
                return;
            }
            msg.setPoints(Math.min(msg.getPoints(), maxPoints - totalPoints));
        }
        PointsRecord pointsRecord = new PointsRecord();
        pointsRecord.setUserId(msg.getUserId());
        pointsRecord.setType(type);
        pointsRecord.setPoints(msg.getPoints());
        this.save(pointsRecord);
        // 5. 保存积分信息到redis 用于排行榜

        LocalDate now = LocalDate.now();
        String format = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX+format;
        redisTemplate.opsForZSet().incrementScore(key, msg.getUserId().toString(), msg.getPoints());
    }

    @Override
    public List<PointsStatisticsVO> queryMyToday() {
        // 1. 获取当前用户
        Long user = UserContext.getUser();
        // 2. 今日时间获取
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime dayStartTime = DateUtils.getDayStartTime(now);
        LocalDateTime dayEndTime = DateUtils.getDayEndTime(now);
        // 3. 分组查询
        QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
        wrapper.select("type", "sum(points) as points");
        wrapper.eq("user_id", user);
        wrapper.between("create_time", dayStartTime, dayEndTime);
        wrapper.groupBy("type");
        List<PointsRecord> list = this.list(wrapper);
        if(CollUtils.isEmpty(list)){
            return CollUtils.emptyList();
        }
        List<PointsStatisticsVO> voList = new ArrayList<>();
        for (PointsRecord pointsRecord : list) {
            PointsStatisticsVO vo = new PointsStatisticsVO();
            vo.setMaxPoints(pointsRecord.getType().getMaxPoints());
            vo.setPoints(pointsRecord.getPoints());
            vo.setType(pointsRecord.getType().getDesc());
            voList.add(vo);
        }
        return voList;
    }
}
